﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
using System.Timers;

namespace BDSim.用户界面.SubWindows
{
    /// <summary>
    /// RealDataHandleWnd.xaml 的交互逻辑
    /// </summary>
    public partial class RealDataHandleWnd : Window
    {
        public RealDataHandleWnd()
        {
            InitializeComponent();
        }

        List<Dictionary<string, Ephemeris_16>> SatEph16DicList = new List<Dictionary<string, Ephemeris_16>>();
        List<Dictionary<string, ClkErrFitMsg>> ClockErrDicList = new List<Dictionary<string, ClkErrFitMsg>>();
        List<Dictionary<string, List<ObsReceiverOutput>>> ObsSatsDataDicList = new List<Dictionary<string, List<ObsReceiverOutput>>>();
        IonoSphere_8 IonEightParam = new IonoSphere_8();
        double[] receiverPos = new double[3];
        CReceiver Receiver = new CReceiver() { Name = "接收机"};

        Timer PVTTimer = new Timer(500);
        /// <summary>
        /// 定位次数
        /// </summary>
        int PPIndex = 0;

        /// <summary>
        /// 使用的导航电文组数
        /// </summary>
        int NavIndex = 0;

        int _NavSystem = 0;

        /// <summary>
        /// 伪距在观测数据中的位置
        /// </summary>
       //int psuedsIndex = 0;

        /// <summary>
        /// 载波相位在观测数据中的位置
        /// </summary>
        //int carriedPhasIndex = 0;

        public int NavSystem
        {
            get { return _NavSystem; }
            set { _NavSystem = value; }
        }


        private void SelectDataFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog opf = new OpenFileDialog();
            if (opf.ShowDialog() == true)
            {
                if ((sender as Button).Name == "btnSelectNav")
                {
                    if (ReadNavMessageData(opf.FileName))
                    {
                        txtNavDataFile.Text = opf.FileName;
                    }
                }
                else if ((sender as Button).Name == "btnSelectObs")
                {
                    if (ReadObsData(opf.FileName))
                    {
                        txtObsDataFile.Text = opf.FileName;
                    }
                }
            }
        }

        #region 读取导航电文数据
        /// <summary>
        /// 读取导航电文数据
        /// </summary>
        /// <param name="fileName"></param>
        bool ReadNavMessageData(string NavMsgDataPath)
        {
            bool flag = false;
            try
            {
                SatEph16DicList.Clear();
                ClockErrDicList.Clear();
                RinexFileDataType.NavMessageHead navHead = new RinexFileDataType.NavMessageHead();
                SatEph16DicList.Add(new Dictionary<string, Ephemeris_16>());
                ClockErrDicList.Add(new Dictionary<string, ClkErrFitMsg>());

                ///判断导航电文类型
                StreamReader sr = new StreamReader(NavMsgDataPath);
                string oneline = sr.ReadLine();
                char[] spilt = { ' ' };
                string[] data = oneline.Split(spilt, StringSplitOptions.RemoveEmptyEntries);
                int NavType = 2;//2表示V2.10, 3表示V3.02
                if (data[0] == "3.02")
                {
                    NavType = 3;
                }

                ///调用C++动态库读取电文文件
                RinexFileDLL.NavOpen(NavMsgDataPath.ToCharArray());

                List<NodePosVel> PVList = new List<NodePosVel>();
                //NavMsgPVList.Add(new Dictionary<int, SatKeyInfo>());

                int streamID = 1;
                int ReadFileFlag = 2;
                ///根据电文类型读导航电文头文件
                if (NavType == 2)
                {
                    ReadFileFlag = RinexFileDLL.NavReadHeader_V210(streamID, out  navHead);
                }
                else if (NavType == 3)
                {
                    ReadFileFlag = RinexFileDLL.NavReadHeader_V302(streamID, out  navHead);
                }

                //填充电离层数据
                FillDataForIonEightParam(navHead, ref IonEightParam);
                while (ReadFileFlag == 1)
                {
                    RinexFileDataType.NavMessage_Rinex NavMsg = new RinexFileDataType.NavMessage_Rinex();
                    ///根据电文类型读一次文件
                    if (NavType == 2)
                    {
                        ReadFileFlag = RinexFileDLL.NavReadRecoder_V210(streamID, out NavMsg);
                    }
                    else if (NavType == 3)
                    {
                        ReadFileFlag = RinexFileDLL.NavReadRecoder_V302(streamID, out NavMsg);
                    }
                    if (ReadFileFlag == -1)
                    {
                        break;
                    }
                    FillEphemeris_16_Clk(NavMsg);
                }
                RinexFileDLL.NavClose(streamID);
                flag = true;
            }
            catch (Exception exp)
            {
                throw exp;
            }
            return flag;
        }

        /// <summary>
        /// 填充电离层8参数据
        /// </summary>
        /// <param name="navHead"></param>
        /// <param name="IonEightParam"></param>
        void FillDataForIonEightParam(RinexFileDataType.NavMessageHead navHead, ref IonoSphere_8 IonEightParam)
        {
            IonEightParam.Alpha0 = navHead.A0;
            IonEightParam.Alpha1 = navHead.A1;
            IonEightParam.Alpha2 = navHead.A2;
            IonEightParam.Alpha3 = navHead.A3;
            IonEightParam.Beta0 = navHead.B0;
            IonEightParam.Beta1 = navHead.B1;
            IonEightParam.Beta2 = navHead.B2;
            IonEightParam.Beta3 = navHead.B3;
        }

        /// <summary>
        /// 填充星历和钟差数据
        /// </summary>
        /// <param name="NavMsg"></param>
        void FillEphemeris_16_Clk(RinexFileDataType.NavMessage_Rinex NavMsg)
        {
            if (NavMsg.SysType == '\0')
            {
                NavMsg.SysType = 'G';
            }
            string satelliteName = NavMsg.SysType.ToString() + NavMsg.PRN;

            Ephemeris_16 Eph_Param16 = new Ephemeris_16();
            Eph_Param16.LoadDataFromRinexNavMsg(NavMsg);
            
            ClkErrFitMsg clk = new ClkErrFitMsg();
            clk.a0 = NavMsg.a0;
            clk.a1 = NavMsg.a1;
            clk.a2 = NavMsg.a2;
            clk.toc = NavMsg.TOE_3;
            clk.FitTime = NavMsg.Epoch;

            //如果保存的最后一组星历中其中一颗卫星星历时间（加上一分钟，部分同时发送的星历时刻可能差一秒）比新的星历时间要早，则新建一组，添加进去，不然则直接添加，钟差类似
            if (SatEph16DicList.Last().Count>0 && (SatEph16DicList.Last().Last().Value.t.ToDateTime().AddMinutes(1).CompareTo(Eph_Param16.t.ToDateTime()) < 0))
            {
                SatEph16DicList.Add(new Dictionary<string, Ephemeris_16>());
                ClockErrDicList.Add(new Dictionary<string, ClkErrFitMsg>());
            }
            //如果不包含当前卫星星历，则添加，不然则丢弃
            if (!SatEph16DicList.Last().Keys.Contains(satelliteName))
            {
                SatEph16DicList.Last().Add(satelliteName, Eph_Param16);
                ClockErrDicList.Last().Add(satelliteName, clk);
            }
        }
        #endregion 读取导航电文数据

        #region 读取观测数据
        /// <summary>
        /// 读取观测数据数据
        /// </summary>
        /// <param name="fileName"></param>
        bool ReadObsData(string ObsDataPath)
        {
            //RinexFileDataType.ObsDataAll_v302 obsDataAll = new RinexFileDataType.ObsDataAll_v302();
            //RinexFileDLL.ReadWholeOBS_V302(ObsDataPath.ToCharArray(), out obsDataAll);
            bool flag = false;
            //try
            //{
            ObsSatsDataDicList.Clear();
                RinexFileDataType.ObserveHead obsHead = new RinexFileDataType.ObserveHead();
                ///判断导航电文类型
                StreamReader sr = new StreamReader(ObsDataPath);
                string oneline = sr.ReadLine();
                char[] spilt = { ' ' };
                string[] data = oneline.Split(spilt, StringSplitOptions.RemoveEmptyEntries);
                int NavType = 2;//2表示V2.10, 3表示V3.02
                if (data[0] == "3.02")
                {
                    NavType = 3;
                }

                ///调用C++动态库读取电文文件
                RinexFileDLL.ObsOpen(ObsDataPath.ToCharArray());

                int streamID = 1;
                int ReadFileFlag = 2;
                ///根据电文类型读导航电文头文件
                if (NavType == 2)
                {
                    ReadFileFlag = RinexFileDLL.ObsReadHeader_V210(streamID, out  obsHead);
                }
                else if (NavType == 3)
                {
                    ReadFileFlag = RinexFileDLL.ObsReadHeader_V302(streamID, out  obsHead);
                }
                

                receiverPos = new double[] { obsHead.ApproxPos.x, obsHead.ApproxPos.y, obsHead.ApproxPos.z };
                while (ReadFileFlag == 1)
                {
                    ///根据电文类型读一次文件
                    
                    if (NavType == 2)
                    {
                        RinexFileDataType.ObserveData obsData210 = new RinexFileDataType.ObserveData();
                        ReadFileFlag = RinexFileDLL.ObsReadRecoder_V210(streamID, ref obsHead, out obsData210);
                        FileObsData210(obsData210);
                    }
                    else if (NavType == 3)
                    {
                        RinexFileDataType.ObserveData_v302 obsData302 = new RinexFileDataType.ObserveData_v302();
                        ReadFileFlag = RinexFileDLL.ObsReadRecoder_V302(streamID, ref obsHead, out obsData302);
                        FileObsData302(obsData302);
                    }
                    if (ReadFileFlag == -1)
                    {
                        break;
                    }
                }
                RinexFileDLL.ObsClose(streamID);
                flag = true;
            //}
            //catch (Exception exp)
            //{
            //    throw exp;
            //}
            return flag;
        }

        void FileObsData210(RinexFileDataType.ObserveData obsData)
        {
            Dictionary<string, List<ObsReceiverOutput>> singleSatObsData = new Dictionary<string, List<ObsReceiverOutput>>();
            
            char sysFlag = NavSystem == 0? 'C':'G';
            for (int satIndex = 0; satIndex < obsData.hdr.SatCount; satIndex++)
            {
                //只取使用定位系统的观测数据
                if (sysFlag == obsData.hdr.SatFlag[satIndex])
                {
                    List<ObsReceiverOutput> obsReceiverOutput = new List<ObsReceiverOutput>();
                    ObsReceiverOutput obs = new ObsReceiverOutput();

                    string satelliteName = obsData.hdr.SatFlag[satIndex].ToString() + obsData.hdr.Prn[satIndex];

                    obs.CurTime = obsData.hdr.Epoch;
                    obs.ReceiverID = 1;
                    obs.SatID = obsData.hdr.Prn[satIndex];
                    //if (obsData.hdr.SatFlag[satIndex] == 'C')
                    //{
                    //    //按照Ublox接收机实测数据格式赋值
                    //    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    //    //obs.SatObs.A_Carri_writein = obsData.Sta2SatObsData[satIndex].ObsValue[1];
                    //    //obs.SatObs.DoplShift = obsData.Sta2SatObsData[satIndex].ObsValue[6];
                    //}
                    //if (obsData.hdr.SatFlag[satIndex] == 'G')
                    //{
                    //    //按照Ublox接收机实测数据格式赋值
                    //    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    //    //obs.SatObs.A_Carri_writein = obsData.Sta2SatObsData[satIndex].ObsValue[1];
                    //}
                    //赋值观测值，只使用单频观测值
                    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    //只考虑单频观测数据
                    obsReceiverOutput.Add(obs);
                    singleSatObsData.Add(satelliteName, obsReceiverOutput);
                }
            }
            ObsSatsDataDicList.Add(singleSatObsData);
        }

        void FileObsData302(RinexFileDataType.ObserveData_v302 obsData)
        {
            Dictionary<string, List<ObsReceiverOutput>> singleSatObsData = new Dictionary<string, List<ObsReceiverOutput>>();
            //ObsSatsDataDic.Add(singleSatObsData);
            char sysFlag = NavSystem == 0 ? 'C' : 'G';
            for (int satIndex = 0; satIndex < obsData.hdr.SatCount; satIndex++)
            {
                //只取使用定位系统的观测数据
                if (sysFlag == obsData.SatSysCode[satIndex])
                {
                    List<ObsReceiverOutput> obsReceiverOutput = new List<ObsReceiverOutput>();
                    ObsReceiverOutput obs = new ObsReceiverOutput();

                    string satelliteName = obsData.SatSysCode[satIndex].ToString() + obsData.SatID[satIndex];

                    obs.CurTime = obsData.hdr.Epoch;
                    obs.ReceiverID = 1;
                    obs.SatID = obsData.SatID[satIndex];
                    //if (obsData.SatSysCode[satIndex] == 'C')
                    //{
                    //    //按照Ublox接收机实测数据格式赋值
                    //    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    //    //obs.SatObs.A_Carri_writein = obsData.Sta2SatObsData[satIndex].ObsValue[3];
                    //    //obs.SatObs.DoplShift = obsData.Sta2SatObsData[satIndex].ObsValue[6];
                    //}
                    //if (obsData.SatSysCode[satIndex] == 'G')
                    //{
                    //    //按照Ublox接收机实测数据格式赋值
                    //    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    //    //obs.SatObs.A_Carri_writein = obsData.Sta2SatObsData[satIndex].ObsValue[1];
                    //}
                    
                    //只考虑单频观测数据
                    obs.SatObs.A_Pseudo_writein = obsData.Sta2SatObsData[satIndex].ObsValue[0];
                    obsReceiverOutput.Add(obs);
                    singleSatObsData.Add(satelliteName, obsReceiverOutput);
                }
            }
            if (singleSatObsData.Count != 0)
            {
                ObsSatsDataDicList.Add(singleSatObsData);
            }
        }
        #endregion 读取观测数据

        
        

        /// <summary>
        /// 根据当前观测数据的组数更新使用的导航电文组数
        /// </summary>
        /// <param name="currentNavIndex"></param>
        void ComputeNavIndex(int currentNavIndex)
        {
            UTCTime obsDataTime = ObsSatsDataDicList[PPIndex].First().Value.First().CurTime;
            UTCTime NavTime = SatEph16DicList[currentNavIndex].First().Value.t;

            while (SatEph16DicList.Count<currentNavIndex && NavTime.ToDateTime().AddHours(2).CompareTo(obsDataTime.ToDateTime()) < 0)
            {
                currentNavIndex++;
                NavTime = SatEph16DicList[currentNavIndex].First().Value.t;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            (Owner as MainWindow).receiverMonitorView.PPositionEvaluationList.Add(Receiver);
            (Owner as MainWindow).receiverMonitorView.OriginDataPPositionInit();
            PVTTimer.Elapsed += new ElapsedEventHandler(PVTTimer_Elapsed);
        }

        void PVTTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (PPIndex < ObsSatsDataDicList.Count)
            {
                ComputeNavIndex(NavIndex);
                this.Dispatcher.Invoke(new Action(() =>
                {
                    Receiver.OriginalDataPVT(SatEph16DicList[NavIndex], ClockErrDicList[NavIndex], ObsSatsDataDicList[PPIndex], IonEightParam, receiverPos);
                }));

                //Receiver.UpdateResult();
                PPIndex++;
            }
            else
            {
                PVTTimer.Enabled = false;
                this.Dispatcher.Invoke(new Action(() =>
                {
                    MessageBox.Show("实测数据定位解算已完成!");
                    btnStartPPosition.IsEnabled = true;
                    btnPause.IsEnabled = false;
                }));
                PPIndex = 0;
                NavIndex = 0;
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            
            Receiver.UpDatePPositionResult = null;
            (Owner as MainWindow).receiverMonitorView.PPositionEvaluationList.Clear();
        }

        private void btnStartPPosition_Click(object sender, RoutedEventArgs e)
        {
            if (SatEph16DicList.Count>0 && ObsSatsDataDicList.Count>0)
            {
                PVTTimer.Enabled = true;
                btnStartPPosition.IsEnabled = false;
                btnPause.IsEnabled = true;
            }
        }

        private void btnPause_Click(object sender, RoutedEventArgs e)
        {
            PVTTimer.Enabled = false;
            btnStartPPosition.IsEnabled = true;
            btnPause.IsEnabled = false;
        }
    }
}
